<link href="http://cdn.bootcss.com/highlight.js/8.0/styles/monokai_sublime.min.css" rel="stylesheet">
<script src="http://cdn.bootcss.com/highlight.js/8.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<h1 id="egret-matchvs">Egret集成Matchvs</h1>
<p>在Egret游戏开发引擎中使用 Matchvs 游戏联网引擎，快速的开发联网对战游戏。</p>
<h2 id="egret-">Egret 环境配置</h2>
<h4 id="1-lanucher-">1、Lanucher 安装。</h4>
<ul>
<li><a href="https://www.egret.com/">Lanucher 下载</a> </li>
</ul>
<h4 id="2-egret-">2、安装egret引擎版。</h4>
<p>打开Lanucher选择对应的egret引擎版本下载安装（egret更新较快建议安装最新的Stableb版本），如下图：</p>
<p><img src="Egret新手上路img/egret_start1.png" alt=""></p>
<h4 id="3-ide-wing">3、安装IDE工具Wing</h4>
<p>打开Lanucher 定位到工具页面，下载wing并安装。</p>
<h2 id="matchvs-">Matchvs 集成</h2>
<h4 id="1-egret-">1、创建egret游戏开发项目。</h4>
<p>打开Lanucher 定位到项目页面。创建项目。在项目创建页面勾选Matchvs游戏云。并创建。</p>
<p><img src="Egret新手上路img/egret_start2.png" alt=""></p>
<h4 id="2-matchvs-">2、替换matchvs文件夹下面的内容</h4>
<p>到 <a href="http://www.matchvs.com/serviceDownload">Matchvs官网下载</a> TypeScript版本的 MatchvsSDK 解压并取出 matchvs 文件内容到 egret项目的libs目录里面。</p>
<blockquote>
<p> <code>matchvs</code>文件下三个文件(matchvs.d.ts、matchvs.js、matchvs.min.js)。</p>
</blockquote>
<h4 id="3-wing-">3、使用 wing打开项目</h4>
<p>创建好项目后，在打开项目的wing左边导航可以的libs目录下可以看到有 matchvs文件夹，如下图：</p>
<p><img src="Egret新手上路img/egret_start3.png" alt=""></p>
<h4 id="4-egretproperties-json-">4、配置 egretProperties.json 文件</h4>
<p>打开 egretProperties.json 文件添加如下配置：</p>
<pre><code class="language-typescript">{
      &quot;name&quot;: &quot;matchvs&quot;,
      &quot;path&quot;: &quot;./libs/matchvs&quot;
 }</code></pre>
<p>如图所示：</p>
<p><img src="Egret新手上路img/egret_start5.png" alt=""></p>
<p>以上步骤已经完美集成 Matchvs SDK，接下来就开启你的 联网对战之旅。</p>
<h2 id="matchvs-">Matchvs 使用</h2>
<p>在使用 Matchvs 服务之前请确认您已经在 Matchvs官网注册账号并新建好了一款游戏服务。如果还没有注册Matchvs 游戏服务请参考 <a href="">Matchvs游戏注册</a> 文档。</p>
<p>Matchvs SDK 接口服务分为 <strong>请求服务</strong> 和 <strong>回调服务</strong> ， 使用是以简单的接口调用和接口返回的方式实现相关联网操作。比如随机加入房间只需要调用<code>joinRandRoom接口</code>，加入房间结果就以接口 <code>joinRoomResponse</code> 返回。在整个使用过程中，开发者只需要关心<code>MatchvsEngine</code>(接口请求调用对象)和 <code>MatchvsResponse</code>(接口调用返回对象)。接口请求使用 <code>MatchvsEngine</code>对象实例，接口返回使用 <code>MatchvsResponse</code> 对象实例。后面后介绍这两个对象的使用方法。此文档只是用于引导开发者接入SDK，需要接口详细的参数说明请看 <a href="http://www.matchvs.com/service?page=ts">API手册</a> </p>
<h4 id="matchvs-">Matchvs 变量定义</h4>
<p>定义两个全局唯一的Matchvs 服务变量，一个是  <code>MatchvsEngine</code> 接口请求对象变量，另一个是<code>MatchvsResponse</code> 接口回调对象。示例代码如下：</p>
<pre><code class="language-typescript">let engine:MatchvsEngine = new MatchvsEngine();
let response:MatchvsResponse = new MatchvsResponse();</code></pre>
<p>在egret 项目中使用示例如下：</p>
<pre><code class="language-typescript">//这Main是Egret项目中的入口
class Main extends eui.UILayer {
    ......
    private engine:MatchvsEngine = new MatchvsEngine();
    private response:MatchvsResponse = new MatchvsResponse();
    ......
}
</code></pre>
<blockquote>
<p>注意：请确保两个对象是全局唯一的，您可以根据自己的喜好进行封装，使用静态变量或者单例类都可以。</p>
</blockquote>
<h4 id="matchvs-">Matchvs 初始化</h4>
<p>获取到对象实例后，需要开发者把 <code>MatchvsResponse</code> 实例注册到 <code>MatchvsEngine</code> 用于注册、登录、加入房间等接口请求后的异步回调。调用 <code>init</code> 接口初始化SDK。</p>
<p>请求示例：</p>
<pre><code class="language-typescript">engine.init(response, &quot;Matchvs&quot;, &quot;alpha&quot;, 201016);</code></pre>
<p>回调示例:</p>
<pre><code class="language-typescript">response.initResponse = function(status:number){
    .......
}</code></pre>
<p>参数说明:</p>
<table>
<thead>
<tr>
<th align="left">参数</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td align="left">status</td>
<td>200-成功 其他失败</td>
</tr>
</tbody></table>
<p>在egret 项目中使用示例如下：</p>
<pre><code class="language-typescript">class Main extends eui.UILayer {
    .....
    private runMatchvs(){
        this.response.initResponse = this.initResponse.bind(this);
        this.engine.init(this.response, &quot;Matchvs&quot;, &quot;alpha&quot;, 201016);
    }

    private initResponse(status:number){
        if(status === 200){
            console.log(&quot;初始化成功!&quot;);
        }
    }
}</code></pre>
<blockquote>
<p>注意：this.response.initResponse = this.initResponse; 是指定 engine.init 请求的回调函数，在调用init前需要指定一个回调函数用于处理回调结果，可以在在统一的一个地方处理你将要使用的回调函数。在示例中我们约定在调用<code>MatchvsEngine</code> 请求接口前指定回调函数。</p>
</blockquote>
<h4 id="-">注册用户</h4>
<p>Matchvs提供的 <code>userID</code> 被用于在各个服务中校验连接的有效性，调试前开发者需要先获取到一个合法的<code>userID</code>。调用registerUser接口获取，在registerResponse回调返回。</p>
<p>请求示例：</p>
<pre><code class="language-typescript">engine.registerUser();</code></pre>
<p>回调示例：</p>
<pre><code class="language-typescript">response.registerUserResponse = function(userInfo:MsRegistRsp){
    ......
}</code></pre>
<blockquote>
<p><strong>注意</strong> : 每次调用 registerUser 接口都会生成新的 <code>userID</code> 为了节省资源消耗， <code>userID</code>和 <code>token</code> 有需要的可以缓存起来，在之后的应用启动中不必重复获取。如果你有自己的用户系统，可以将Matchvs 提供的 userID 和用户系统进行映射。可以参考 <a href="http://www.matchvs.com/service?page=third">Matchvs 第三方账号绑定</a>，让您的用户唯一对应一个userID，以节省资源。</p>
<p>为了资源节省，我们在registerUserResponse 回调前把userID信息缓存在本地，数据会暂存在浏览器中。所以使用同一个浏览器调用 registerUser 接口会返回相同的 userID信息。请看 <a href="http://www.matchvs.com/service?page=MultipleIdentities">多开说明</a> </p>
</blockquote>
<p>在egret 项目中使用示例如下：</p>
<pre><code class="language-typescript">//这是初始化成功的回调，我们初始化成功后调用 registerUser 注册用户
private initResponse(status:number){
    if(status === 200){
        console.log(&quot;初始化成功!&quot;);
        this.response.registerUserResponse = this.registerUserResponse.bind(this);
        this.engine.registerUser();
    }
}
//注册用户回调
private registerUserResponse(userInfo:MsRegistRsp){
    if(userInfo.status === 0){
        console.log(&quot;注册成功&quot;);
    }
}</code></pre>
<h4 id="-matchvs-sdk-">登录Matchvs SDK 联网服务</h4>
<p>成功获取 <code>userID</code> 后即可连接Matchvs服务。调用 login 接口登录，loginResponse 回调。</p>
<p>请求示例：</p>
<pre><code class="language-typescript">engine.login(userInfo.userID, userInfo.token, 201016, 1, &quot;xxxxxappkey&quot;, &quot;xxxxxsecret&quot;, &quot;v&quot;, 0);</code></pre>
<p>回调示例：</p>
<pre><code class="language-typescript">response.loginResponse = function(rsp:MsLoginRsp){
    ......
}</code></pre>
<ul>
<li>其中，appKey，secret，gameID是你在Matchvs官网创建游戏后获取的信息，可以<a href="http://www.matchvs.com/manage/gameContentList">前往控制台</a>查看。appkey和secret是校验游戏合法性的关键信息，请妥善保管secret信息。  </li>
<li>userID 和 token 是调用 registerUser 接口 <strong>注册成功</strong> 的回调信息。</li>
<li>deviceID 用于检测是否存在多个设备同时登录同一个用户的情况，如果一个账号在两台设备上登录，则后登录的设备会连接失败。</li>
<li>Matchvs默认将相同游戏版本的用户匹配到一起。如果开发者对游戏进行了版本升级，不希望两个版本的用户匹配到一起，此时可以在登录的时候通过<code>gameVersion</code>区分游戏版本。 </li>
</ul>
<p>在egret 项目中使用示例如下：</p>
<pre><code class="language-typescript">private registerUserResponse(userInfo:MsRegistRsp){
    if(userInfo.status == 0){
        console.log(&quot;注册成功&quot;);
        this.response.loginResponse = this.loginResponse.bind(this);
        this.engine.login(userInfo.userID, userInfo.token, 201489, 1, &quot;xxxxxappkey&quot;, &quot;xxxxxsecret&quot;, &quot;v&quot;,0);
    }
}

private loginResponse(rsp:MsLoginRsp){
    if(rsp.status === 200){
        console.log(&quot;登录Matchvs联网SDK成功&quot;);
    }
}</code></pre>
<h4 id="-">随机匹配</h4>
<p>登录成功后，可以调用Matchvs加入房间接口，将若干用户匹配至一个房间开始一局游戏（如：《荒野行动》的开始匹配、《球球大作战》的开始比赛等）</p>
<p>Matchvs默认提供了随机加入房间的模式，调用加入房间逻辑后，Matchvs服务器会自动帮助用户寻找当前可用房间，只有在同一个房间里的用户才可以互相通信。</p>
<p>随机加入房间的模式下，Matchvs服务器能够快速找到合适的房间，开发者只需要自定义房间人数上限，Matchvs服务端会根据当前房间人数判断是否可继续加入。  加入房间回调有 joinRoomResponse 和 joinRoomNotify 两个，前者是调用joinRoom者受到是否成功加入房间回调的信息，后者是在房间其他的玩家收到的回调信息。</p>
<p>请求示例：</p>
<pre><code class="language-typescript">engine.joinRandomRoom(3,&quot;hello matchvs&quot;);</code></pre>
<p>回调示例：</p>
<pre><code class="language-typescript">this.response.joinRoomNotify = function(roomUserInfo:MsRoomUserInfo){
    ......
}

this.response.joinRoomResponse = function(status:number, roomUserInfoList: Array &lt;MsRoomUserInfo&gt;, roomInfo:MsRoomInfo){
    ......
}</code></pre>
<p>在 Egret  项目中使用示例如下：</p>
<pre><code class="language-typescript">private loginResponse(rsp:MsLoginRsp){
    if(rsp.status === 200){
        console.log(&quot;登录Matchvs联网SDK成功&quot;);
        this.response.joinRoomNotify = this.joinRoomNotify.bind(this);
        this.response.joinRoomResponse = this.joinRoomResponse.bind(this);
        this.engine.joinRandomRoom(3,&quot;hello matchvs&quot;);
    }else{
        console.log(&quot;登录Matchvs联网失败&quot;,userInfo.status );
    }
}

private joinRoomResponse(status:number, roomUserInfoList:Array&lt;MsRoomUserInfo&gt;, roomInfo:MsRoomInfo){
    if(status === 200){
        console.log(&quot;我自己进入房间成功&quot;);
    }
}

private joinRoomNotify(roomUserInfo:MsRoomUserInfo){
    console.log(&quot;有其他人进入房间&quot;);
}</code></pre>
<p>Matchvs 提供四种加入房间的操作，他们加入房间的操作都是相互平行的，随机匹配只能和随机配的玩家一起，属性匹配只能和属性匹配的玩家一起，但是加入指定房间 与 创建房间是一起的：</p>
<ul>
<li>随机匹配( joinRandRoom ): 由Matchvs 自动匹配用户。</li>
<li>属性匹配( joinRoomWithProperties ): 由开发设定属性相同的用户匹配到一起</li>
<li>加入指定房间 ( joinRoom )：加入指定房间，这个是与 createRoom配合使用，只能加入到 createRoom 创建的房间。</li>
<li>创建房间( createRoom )：开发者自己创建房间。其他玩家要加入必须使用 joinRoom 加入。</li>
</ul>
<h3 id="-">完整示例代码</h3>
<pre><code class="language-typescript">
class Main extends eui.UILayer {

    private engine:MatchvsEngine = new MatchvsEngine();
    private response:MatchvsResponse = new MatchvsResponse();

    protected createChildren(): void {
        super.createChildren();

        //注入自定义的素材解析器
        let assetAdapter = new AssetAdapter();
        egret.registerImplementation(&quot;eui.IAssetAdapter&quot;, assetAdapter);
        egret.registerImplementation(&quot;eui.IThemeAdapter&quot;, new ThemeAdapter());

        this.runGame().catch(e =&gt; {
            console.log(e);
        })
    }

    private async runGame() {
        await this.loadResource()
        this.createGameScene();
        const result = await RES.getResAsync(&quot;description_json&quot;)
        await platform.login();
        const userInfo = await platform.getUserInfo();
        console.log(userInfo);

    }

    private async loadResource() {
        try {
            const loadingView = new LoadingUI();
            this.stage.addChild(loadingView);
            await RES.loadConfig(&quot;resource/default.res.json&quot;, &quot;resource/&quot;);
            await this.loadTheme();
            await RES.loadGroup(&quot;preload&quot;, 0, loadingView);
            this.stage.removeChild(loadingView);
        }
        catch (e) {
            console.error(e);
        }
    }

    private loadTheme() {
        return new Promise((resolve, reject) =&gt; {
            // load skin theme configuration file, you can manually modify the file. And replace the default skin.
            //加载皮肤主题配置文件,可以手动修改这个文件。替换默认皮肤。
            let theme = new eui.Theme(&quot;resource/default.thm.json&quot;, this.stage);
            theme.addEventListener(eui.UIEvent.COMPLETE, () =&gt; {
                resolve();
            }, this);

        })
    }

    private textfield: egret.TextField;
    /**
     * 创建场景界面
     * Create scene interface
     */
    protected createGameScene(): void {
        let sky = this.createBitmapByName(&quot;bg_jpg&quot;);
        this.addChild(sky);
        let stageW = this.stage.stageWidth;
        let stageH = this.stage.stageHeight;
        sky.width = stageW;
        // sky.height = stageH;
        this.runMatchvs();
    }
    /**
     * 根据name关键字创建一个Bitmap对象。name属性请参考resources/resource.json配置文件的内容。
     * Create a Bitmap object according to name keyword.As for the property of name please refer to the configuration file of resources/resource.json.
     */
    private createBitmapByName(name: string): egret.Bitmap {
        let result = new egret.Bitmap();
        let texture: egret.Texture = RES.getRes(name);
        result.texture = texture;
        return result;
    }

    private runMatchvs(){
        this.response.initResponse = this.initResponse.bind(this);
        this.engine.init(this.response, &quot;Matchvs&quot;, &quot;alpha&quot;, 201479);
    }

    private initResponse(status:number){
        if(status === 200){
            console.log(&quot;初始化成功!&quot;);
            this.response.registerUserResponse = this.registerUserResponse.bind(this);
            this.engine.registerUser();
        }
    }

    private registerUserResponse(userInfo:MsRegistRsp){
        if(userInfo.status == 0){
            console.log(&quot;注册成功&quot;);
            this.response.loginResponse = this.loginResponse.bind(this);
            this.engine.login(userInfo.userID, userInfo.token, 201479, 1, &quot;xxxxxxxxxxxxxxxxxxxxx&quot;,&quot;xxxxxxxxxxxxxxxxxxxx&quot;,&quot;v&quot;,0);
        }else{
            console.log(&quot;注册失败&quot;,userInfo.status );
        }
    }

    private loginResponse(rsp:MsLoginRsp){
        if(rsp.status == 200){
            console.log(&quot;登录Matchvs联网SDK成功&quot;);
            this.response.joinRoomNotify = this.joinRoomNotify.bind(this);
            this.response.joinRoomResponse = this.joinRoomResponse.bind(this);
            this.engine.joinRandomRoom(3,&quot;hello matchvs&quot;);
        }
    }

    private joinRoomResponse(status:number, roomUserInfoList:Array&lt;MsRoomUserInfo&gt;, roomInfo:MsRoomInfo){
        if(status === 200){
            console.log(&quot;我自己进入房间成功&quot;);
        }
    }
    private joinRoomNotify(roomUserInfo:MsRoomUserInfo){
        console.log(&quot;有其他人进入房间&quot;);
    }
}</code></pre>
<h3 id="-matchvs-sdk-">下一步 <a href="">Matchvs SDK 基础功能使用</a></h3>
